package com.cosytek.farmmanager;

import android.os.Handler;

import com.koushikdutta.async.callback.CompletedCallback;
import com.koushikdutta.async.http.AsyncHttpClient;
import com.koushikdutta.async.http.AsyncHttpGet;
import com.koushikdutta.async.http.WebSocket;

import java.util.concurrent.Future;

/**
 * Created by Happy on 2015/3/26.
 */
public class WebSocketWrapper implements AsyncHttpClient.WebSocketConnectCallback, WebSocket.StringCallback, CompletedCallback {
    private static final String ACCOUNT_HEADER = "account";
    private static final String PASSWORD_HEADER = "password";

    private WebSocket mWebSocket;
    private final String mWSUrl;
    private final String mPassword;
    private final String mAccount;
    private final Handler  mWorkHandler;

    private Future<WebSocket> mFutureWebSocket;
    private OnWebSocketListener mListener;
    private static final int KEEP_ALIVE_PERIOD = (300 * 1000);

    private final Runnable keepAliveRunnable = new Runnable() {

        @Override
        public void run() {
            doKeepAlive();
            startKeepAliveTimer();
        }
    };

    public void close() {
        mListener = null;
        if (mFutureWebSocket != null) {
            mFutureWebSocket.cancel(true);
        }

        if (mWebSocket != null) {
            mWebSocket.setStringCallback(null);
            mWebSocket.setClosedCallback(null);
            mWebSocket.close();
        }

        stopKeepAliveTimer();
    }

    public interface OnWebSocketListener {
        void onStringReceived(String data);
        void onWebSocketBreak();
        Handler getWorkHandler();
    }

    public WebSocketWrapper(String url, String account, String password, OnWebSocketListener listener) {
        mWSUrl = url;
        mAccount = account;
        mPassword = password;
        mWorkHandler = listener.getWorkHandler();
        mListener = listener;
    }

    public void connect() {
        AsyncHttpGet get = new AsyncHttpGet(mWSUrl);
        get.addHeader(ACCOUNT_HEADER, mAccount);
        get.addHeader(PASSWORD_HEADER, mPassword);

        mFutureWebSocket = AsyncHttpClient.getDefaultInstance().websocket(get,
                null, this);
    }

    /**
     * WebSocketConnectCallback implementation.
     * @param ex exception.
     * @param webSocket web socket object.
     */
    @Override
    public void onCompleted(Exception ex, WebSocket webSocket) {
        mFutureWebSocket = null;

        if (ex != null) {
            onCompleted(ex);
            return;
        }

        mWebSocket = webSocket;
        mWebSocket.setStringCallback(this);
        mWebSocket.setClosedCallback(this);

        startKeepAliveTimer();
    }

    @Override
    public void onStringAvailable(final String s) {
        mWorkHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mListener != null) {
                    mListener.onStringReceived(s);
                }
            }
        });
    }

    /**
     * CompletedCallback implementation.
     * @param ex exception.
     */
    @Override
    public void onCompleted(Exception ex) {
        if (ex != null) {
            ex.printStackTrace();
        }

        if (mWebSocket != null) {
            mWebSocket.close();
            mWebSocket = null;
        }

        stopKeepAliveTimer();

        mWorkHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mListener != null) {
                    mListener.onWebSocketBreak();
                }
            }
        });
    }

    private void startKeepAliveTimer() {
        mWorkHandler.postDelayed(keepAliveRunnable, KEEP_ALIVE_PERIOD);
    }

    private void stopKeepAliveTimer() {
        mWorkHandler.removeCallbacks(keepAliveRunnable);
    }

    private void doKeepAlive() {
        if (mWebSocket != null) {
            mWebSocket.send("hello, server!");
        }
    }
}
